// 导出函数和类型
import type {
  IndexAlias,
  IndexField,
  IndexMeta,
  IndexSetting,
  IndexShard,
  RawIndexData,
  UpdateResult
} from "./types";

/**
 * 计算索引元数据的变更，返回需要执行的数据库操作
 * @param currentRawData - 当前从接口获取的原始数据
 * @param existingMeta - 数据库中已存在的主元数据
 * @param existingAliases - 数据库中已存在的别名列表
 * @param existingFields - 数据库中已存在的字段列表
 * @param existingSettings - 数据库中已存在的设置列表
 * @param existingShards - 数据库中已存在的分片列表
 * @returns 包含增删改操作的对象
 */
export function calculateIndexMetaChanges(
  currentRawData: RawIndexData,
  existingMeta: IndexMeta | null,
  existingAliases: IndexAlias[],
  existingFields: IndexField[],
  existingSettings: IndexSetting[],
  existingShards: IndexShard[]
): UpdateResult {
  const now = Math.floor(Date.now() / 1000);
  let hasChanges = false;

  // 1. 检查主元数据是否有变化（主要是hash）
  let indexMetaToUpdate: IndexMeta[] = [];
  let indexMetaToInsert: IndexMeta[] = [];

  if (existingMeta) {
    // 如果hash不同，则需要更新主元数据
    if (existingMeta.hash !== currentRawData.hash) {
      hasChanges = true;
      indexMetaToUpdate = [
        {
          ...existingMeta,
          hash: currentRawData.hash,
          updated_at: now
        }
      ];
    }
  } else {
    // 如果不存在，则插入新的主元数据
    hasChanges = true;
    // 注意：这里需要生成一个ID，实际使用时应由调用方提供或生成
    indexMetaToInsert = [
      {
        index_name: currentRawData.index_name,
        hash: currentRawData.hash,
        created_at: now,
        updated_at: now
      }
    ];
  }

  // 2. 计算别名变化
  const { toDelete: aliasToDelete, toInsert: aliasToInsert } = calculateChanges(
    existingAliases,
    currentRawData.aliases.map((name) => ({
      alias_name: name
    })),
    "alias_name",
    (item, metaId) => ({
      meta_id: metaId,
      alias_name: item.alias_name,
      created_at: now,
      updated_at: now
    }),
    existingMeta?.id || ""
  );

  // 3. 计算字段变化
  const { toDelete: fieldToDelete, toInsert: fieldToInsert } = calculateChanges(
    existingFields,
    currentRawData.fields.map((f) => ({
      field_path: f.field_path,
      field_type: f.field_type,
      is_aggregatable: f.is_aggregatable,
      is_searchable: f.is_searchable,
      analyzer: f.analyzer || ""
    })),
    "field_path",
    (item, metaId) => ({
      meta_id: metaId,
      field_path: item.field_path,
      field_type: item.field_type,
      is_aggregatable: item.is_aggregatable,
      is_searchable: item.is_searchable,
      analyzer: item.analyzer,
      created_at: now,
      updated_at: now
    }),
    existingMeta?.id || ""
  );

  // 4. 计算设置变化
  const settingsList = Object.entries(currentRawData.settings).map(([k, v]) => ({
    setting_key: k,
    setting_value: v
  }));
  const { toDelete: settingToDelete, toInsert: settingToInsert } = calculateChanges(
    existingSettings,
    settingsList,
    "setting_key",
    (item, metaId) => ({
      meta_id: metaId,
      setting_key: item.setting_key,
      setting_value: item.setting_value,
      created_at: now,
      updated_at: now
    }),
    existingMeta?.id || ""
  );

  // 5. 计算分片变化
  const { toDelete: shardToDelete, toInsert: shardToInsert } = calculateChanges(
    existingShards,
    currentRawData.shards.map((s) => ({
      shard_id: s.shard_id,
      shard_type: s.shard_type,
      node_name: s.node_name,
      state: s.state
    })),
    "shard_id",
    (item, metaId) => ({
      meta_id: metaId,
      shard_id: item.shard_id,
      shard_type: item.shard_type,
      node_name: item.node_name,
      state: item.state,
      created_at: now,
      updated_at: now
    }),
    existingMeta?.id || ""
  );

  // 检查是否有任何子表数据变化
  if (!hasChanges) {
    hasChanges = [
      aliasToInsert.length > 0,
      aliasToDelete.length > 0,
      fieldToInsert.length > 0,
      fieldToDelete.length > 0,
      settingToInsert.length > 0,
      settingToDelete.length > 0,
      shardToInsert.length > 0,
      shardToDelete.length > 0
    ].some(Boolean);
  }

  return {
    indexMeta: {
      toUpdate: indexMetaToUpdate,
      toInsert: indexMetaToInsert
    },
    aliases: {
      toDelete: aliasToDelete,
      toInsert: aliasToInsert
    },
    fields: {
      toDelete: fieldToDelete,
      toInsert: fieldToInsert
    },
    settings: {
      toDelete: settingToDelete,
      toInsert: settingToInsert
    },
    shards: {
      toDelete: shardToDelete,
      toInsert: shardToInsert
    },
    hasChanges
  };
}

/**
 * 通用的变更计算函数
 * @param existingList - 数据库中已存在的列表
 * @param currentList - 当前数据列表
 * @param keyField - 用于比较的键字段名
 * @param mapToRecord - 将当前数据项映射为数据库记录的函数
 * @param metaId - 关联的meta_id
 * @returns 包含待删除ID列表和待插入记录列表的对象
 */
function calculateChanges<T extends { [key: string]: any }, U>(
  existingList: T[],
  currentList: U[],
  keyField: keyof U,
  mapToRecord: (item: U, metaId: string) => T,
  metaId: string
): { toDelete: string[]; toInsert: T[] } {
  const existingKeys = new Set(existingList.map((item) => item[keyField as any]));
  const currentKeys = new Set(currentList.map((item) => item[keyField]));

  // 找出需要删除的项
  const itemsToDelete = existingList.filter((item) => !currentKeys.has(item[keyField as any]));
  const idsToDelete = itemsToDelete.map((item) => item.id);

  // 找出需要插入的项
  const itemsToInsert = currentList.filter((item) => !existingKeys.has(item[keyField]));
  const recordsToInsert = itemsToInsert.map((item) => mapToRecord(item, metaId));

  return {
    toDelete: idsToDelete,
    toInsert: recordsToInsert
  };
}
